import os
import queue
import sys
import time
import threading
from flask import Flask, redirect
from flask_sock import Sock
from .blueprints.websocket import ControlWebsocket
from .communication import UDPListener, get_local_ip
from .models import WifiDevice, WSMessages, WSSpeedControlMsg, WSSwitchControlMsg
from .services import DevicesManager
from shared_types import ConnectedMsg, UpHeartbeatMsg
from esp_toytrain_client import ESPObject
from .blueprints import blueprint_devices, blueprint_turnouts, blueprint_program_management
from .configs import config_file_mgr
import logging
logging.basicConfig(level=logging.INFO, stream=sys.stderr)
devices_manager = DevicesManager(config_file_mgr.dir)

listener = UDPListener()
listener.start()

# os.system("cls")
print("waiting for ESP Toytrain to connect...")

# 配置flask的静态路径，index.html重定向到根路径
app = Flask(__name__, static_url_path="/",
            static_folder=os.path.join(os.path.abspath(os.path.dirname(__file__)),
                                       "./static"
                                       ))
@app.route("/")
def handle_index():
    return redirect('/static/index.html', code=301)


sock = Sock(app)

control_ws = ControlWebsocket(sock, "/api/control")


def ws_msg_handler(ws: ControlWebsocket, data: WSSpeedControlMsg):
    dev = devices_manager.get_device_by_name(data['train_name'])
    print(devices_manager.get_all_devices(), data)
    if dev is not None:
        dev.set_speed(data["throttle_value"], data['traction_mode'])
    else:
        ws.send_data({"msg": f"Device not found for {data['train_name']}."})


def ws_switch_msg_handler(ws: ControlWebsocket, data: WSSwitchControlMsg):
    dev = devices_manager.get_device_by_name(data['control_name'])
    print(devices_manager.get_all_devices(), data)
    if dev is not None:
        dev.set_switch(data["switch_index"], data["state"])
    else:
        ws.send_data({"msg": f"Device not found for {data['control_name']}."})


def start_app():
    app.register_blueprint(blueprint_devices)
    app.register_blueprint(blueprint_turnouts)
    app.register_blueprint(blueprint_program_management)
    print(app.url_map)
    control_ws.register_msg_handler("throttle", ws_msg_handler)
    control_ws.register_msg_handler("switch", ws_switch_msg_handler)
    app.run(host="0.0.0.0", port=5780)


th = threading.Thread(target=start_app)
th.daemon = True
th.start()


def evt_main():
    while 1:
        # time.sleep(0.5)
        try:
            msg = listener.msg_queue.get(timeout=2)
            # 向前端推送日志消息
            # 时间戳改为毫秒的整数。
            control_ws.send_data(control_ws.msg_to_log(msg))
            if msg["type"] == "ETT_JOIN":
                msg: ConnectedMsg
                local_ip = get_local_ip(msg["ip"], msg["mask"])
                dev = WifiDevice.from_connected_msg(msg)
                print(dev)
                devices_manager.add_device(dev)
                control_ws.send_data(
                    {"msg": f"device joined: {dev.to_json()}"})
                try:
                    obj = ESPObject(msg["ip"], 80)
                    obj.initialize(local_ip)
                    cfg = devices_manager.dev_cfg_mgr.get_config(dev.name)
                    assert cfg is not None
                    obj.upload_functional_configs(cfg)
                    print(obj.get_functional_configs())
                except ConnectionResetError as e:
                    import traceback

                    traceback.print_exc()
                    print(e)
            elif msg['type'] == "ETT_HEARTBEAT_UP":  # 心跳信息
                msg: UpHeartbeatMsg
                device_name = msg['name']
                devices_manager.update_device_heartbeat_time(device_name)

        except queue.Empty:
            continue
        except KeyboardInterrupt:
            break


th2 = threading.Thread(target=evt_main)
th2.daemon = True
th2.start()

while True:
    data = input(">>")

    devs = devices_manager.get_all_devices()
    for dev in devs:
        if data == "play":
            dev.send_audio_control_msg(devices_manager.udp_sender, "play")
        elif data == "stop":
            dev.send_audio_control_msg(devices_manager.udp_sender, "stop")
